<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of MapperAbstract
 *
 * @author andylowe
 */
abstract class Dealscombined_Db_Mapper_MapperAbstract {
    
    protected $_acl;
    protected $_userRoles;
    protected $_dbTable;
    protected $_dbModel;
    protected $_options = array();
    protected $_aclFlag;
    protected $_cache;
    protected $_cacheConfig;
    protected $_cacheEnabled = true;
    
    protected $_nonTableFields = array();
    
    public function __construct($config = null)
    {
        if ($config) {
            $this->changeConfig($config);
        }
    }
    
    public function setDbTable($dbTable)
    {
        if (is_null($this->_dbTable)) {
            if (is_string($dbTable)) {
                $dbTable = new $dbTable($this->getOptions());
            }
            if (!$dbTable instanceof Zend_Db_Table_Abstract) {
                throw new Exception('Invalid table data gateway provided');
            }
        } else {

            $dbTable = new $this->_dbTable($this->getOptions());
        }
        $this->_dbTable = $dbTable;
        return $this;
    }

    public function getDbTable()
    {
        if (null === $this->_dbTable) {
            throw new Exception('No table data gateway specified');
        } elseif (is_string($this->_dbTable)) {
            $this->_dbTable = new $this->_dbTable($this->getOptions());
        }
        return $this->_dbTable;
    }
    
    public function changeConfig(Zend_Config $config)
    {
        $db = Zend_Db::factory($config->database);
        $options = array("db" => $db);
        $this->setOptions($options);
        return $this;
    }
    
    /**
     * 
     */
    protected function _count($where = array())
    {
        if ($where instanceof Zend_Db_Select) {
            $select = $where->setIntegrityCheck(false);
        } elseif (is_array($where)) {
            $select = $this->getDbTable()->select()->setIntegrityCheck(false);
            $select->from($this->getDbTable()->getName(), "count(id) as num_of_records");
            if (count($where) > 0) {
                foreach ($where as $key => $value) {
                    $select->where($key, $value);
                }
            }
        } else {
            throw new Zend_Exception("Filtering must be set by a Zend Db Select object or by an array");
        }
        
        
        $rowset = $this->getDbTable()->fetchAll($select);
        $result = $rowset->current()->toArray();
        return $result['num_of_records'];
    }
    
    protected function _save(Dealscombined_Models_ModelAbstract $model)
    {
        $data = $this->_convertToUnderScore($model->toArray());
        $data = $this->_removeNonTableFields($data);
        
        if (null === ($id = $model->getId())) {
            unset($data['id']);
            $returnData = $this->getDbTable()->insert($data);
        } else {
            $returnData = $this->getDbTable()->update($data, array('id = ?' => $id));
        }
        
        
        return $returnData;
    }

    public function find($id)
    {
        $result = $this->getDbTable()->find($id);
        if (0 == count($result)) {
            $entry = null;
        } else {
            $row = $result->current();
            $entry = new $this->_dbModel($row->toArray());
        }
        return $entry;
    }

    public function fetchAll($where = null, $order = null, $count = null, $offset = null)
    {
        
        $resultSet = $this->getDbTable()->fetchAll($where, $order, $count, $offset);
        $entries   = array();
        foreach ($resultSet as $row) {
            $entry = new $this->_dbModel($row->toArray());
            $entries[] = $entry;
        }
        
        return $entries;
    }
    protected function _findBySearch($where = null, $order = null, $count = null, $offset = null)
    {
        $result = $this->getDbTable()->fetchAll($where, $order, $count, $offset);
        $row = $result->current();
        
        $entry = null;
        if (is_object($row)) {
            $entry = new $this->_dbModel($row->toArray());
        }
        
        return $entry;
    }
    
    public function _delete($params)
    {
        return $this->getDbTable()->delete($params);
    }
    
    protected function _convertToUnderScore(array $data)
    {
        $newData = array();
        foreach ($data as $key => $value) {
            $newKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $key));
            $newData[$newKey] = $value;
        }
        
        return $newData;
    }
    
   
    
    protected function _saveAcltoCache()
    {
        $cache = Zend_Registry::get("cache");
        $acl = FuseDriver_Acl();
        $cache->save($acl, 'acl');
        return $acl;
    }
    
    public function setUserRoles($userRoles)
    {
        $this->_userRoles = $userRoles;
        return $this;
    }
    
    
    public function getUserRoles()
    {
        if (is_null($this->_userRoles)) {
            $identity = Zend_Auth::getInstance()->getIdentity();
            $this->setUserRoles($identity->roles);
        }
        return $this->_userRoles;
    }
    
    /*public function __call($method, $arguments = array())
    {
        $data = null;
        $resource = null;
        $privilege = null;
        $acl = $this->getAcl();
        
        if ($this->getAclFlag()) {
            $config = new Zend_Config_Ini(APPLICATION_PATH."/configs/application.ini", APPLICATION_ENV);
            $roles = array(new Application_Model_Role(array("id" => 0, "name" => $config->acl->application->role)));
        } else {
            $roles = $this->getUserRoles();
            $resource = $this->_createAclResourceForChecking($method, $arguments);
            $privilege = $this->_createAclPrivilegeForChecking($method, $arguments);
            
            
       }
        $acl->setRolesForChecking($roles);
        
        if($acl->isAllowed($resource, $privilege)) {
            $cache = $this->getCache();
            $cacheEnabled = $this->getCacheEnabled();
            
            $params = null;
            if (isset($arguments[0]) && $method !== "save" && $method !== "delete") {
                if($arguments[0] instanceof FuseDriver_Models_ModelAbstract) {
                    $arguments[0] = $arguments[0]->toArray();
                }
                
                if(is_array($arguments[0])) {
                    $params = $this->_createStringFromArrayKeyValues($arguments[0]);
                }
                elseif(!is_object($arguments[0])) {
                    $params = $arguments[0];
                }
                
                $key = preg_replace("/[^a-zA-Z0-9_^]/","",get_class($this)."||$method||$params");

                $cacheData = $cache->fetchResults($key);
            }
            
            if (isset($cacheData) && $cacheData && $cacheEnabled && APPLICATION_ENV === "production") {
                $data = $cacheData;
            } else {
                $method = "_".$method;
                $data = call_user_func_array(array($this, $method), $arguments);
                
                if (isset($key) && $method !== "save" && $method !== "delete") {
                    $cache->saveResults($key, $data);
                }
            }
        }
        return $data;
    }
    
    protected function _createStringFromArrayKeyValues(array $array)
    {
        $string = "";
        
        foreach ($array as $key => $value) {
            if($value instanceof Dealscompared_Models_ModelAbstract) {
                $subarray = $value->toArray();
                
                foreach ($subarray as $subkey => $subvalue) {
                    $string .= "$subkey$subvalue||";
                }
            }
            else {
                $string .= "$key$value||";
            }
        }
        
        return $string;
    }
    
    public function setAclFlag($aclFlag)
    {
        $this->_aclFlag = $aclFlag;
        return $this;
    }
    
    public function getAclFlag()
    {
        return $this->_aclFlag;
    }*/
    
    protected function _removeNonTableFields($data)
    {
        foreach ($this->_nonTableFields as $notTableField) {
            unset($data[$notTableField]);
        }
        return $data;
    }
    
    public function setOptions(array $options)
    {
        $this->_options = $options;
        return $this;
    }
    
    public function getOptions()
    {
        return $this->_options;
    }
    
    public function addOption($key, $value)
    {
        $this->_options[$key] = $value;
        return $this;
    }
    
 
    
    public function getCache()
    {
        if (is_null($this->_cache)) {
            if (is_null($this->getCacheConfig())) {
                $this->setCacheConfig(APPLICATION_PATH."/configs/mappers/base.ini");
            }
            $cache = new FuseDriver_Cache($this->getCacheConfig());
            $this->setCache($cache);
        }
        return $this->_cache;
    }
    
    public function setCacheConfig($cacheConfig)
    {
        $this->_cacheConfig = $cacheConfig;
        return $this;
    }
    
    public function getCacheConfig()
    {
        return $this->_cacheConfig;
    }
    
    public function setCacheEnabled($cacheEnabled)
    {
        $this->_cacheEnabled = $cacheEnabled;
        return $this;
    }
    
    public function getCacheEnabled()
    {
        return $this->_cacheEnabled;
    }
    
    protected function _addParamsToQuery($select, $where = array(), $order = null, $count = null, $offset = null)
    {
        if ($select instanceof Zend_Db_Table_Select) {
            if (count($where) > 0) {
                foreach ($where as $key => $value) {
                    $select->where($key, $value);
                }
            }
            if (is_array($order)) {
                foreach ($order as $orderCol) {
                    $select->order($orderCol);
                }
            } elseif($order) {
                $select->order($order);
            }

            if ($count) {
                if ($offset) {
                    $select->limit($count, $offset);
                } else {
                    $select->limit($count);
                }
            }
        }
        
        return $select;
    }
    
    /*abstract protected function _createAclResourceForChecking($method, $arguments);
    
    abstract protected function _createAclPrivilegeForChecking($method, $arguments);*/
}
